package com.base.core.exception;

import com.base.core.result.ResponseCodeEnum;
import com.base.core.utils.R;
import org.springframework.lang.Nullable;

/**
 * 服务异常
 *
 * 参考 https://www.kancloud.cn/onebase/ob/484204 文章
 * code 第1位（错误提示级别）,第2-3位（错误模块）,第4-7位（错误代码）
 *
 * 咱们不管是查询还是写入或更新操作，所有的操作成功都统一返回 0，代表操作成功。
 *
 * 除了 0 以外，其他的错误码 全都是 7 位数。
 *
 * 7位数 中的 第一位 代表了 错误级别， 1 为业务逻辑级别的错误， 2 为系统级别的错误。 共 9 种错误级别的位置，剩下的开发者有需要可自行扩展。
 *
 * 第二位和第三位 为系统的错误模块定位号码，例如咱们可以看到 签名有 00的 后面 还有 01的， 作者把接口验证相关的错误码归为了 00 模块，
 * 这样 以后一看到错误码就知道是哪里有问题啦，用户相关的验证 为 01 模块，后面还有 90多个模块位置 留着给研发者扩展哦。
 *
 * 最后一组是 第四位到第七位，代表详细的错误位置定位号码，通过这 七位 号码 咱们开发者可以直接定位错误原因，然后迅速找到解决方案。
 *
 * 一共 10 位，分成四段
 *
 * 第一段，1 位，类型
 *      1 - 业务级别异常
 *      2 - 系统级别异常
 * 第二段，3 位，系统类型
 *      001 - 用户系统
 *      002 - 商品系统
 *      003 - 订单系统
 *      004 - 支付系统
 *      005 - 优惠劵系统
 *      ... - ...
 * 第三段，3 位，模块
 *      不限制规则。
 *      一般建议，每个系统里面，可能有多个模块，可以再去做分段。以用户系统为例子：
 *          001 - OAuth2 模块
 *          002 - User 模块
 *          003 - MobileCode 模块
 * 第四段，3 位，错误码
 *       不限制规则。
 *       一般建议，每个模块自增。
 */
public final class ServiceException extends RuntimeException {

    @Nullable
    private final R<?> result;

    private String message;

    public ServiceException(R<?> result) {
        super(result.getMsg());
        this.result = result;
        this.message = result.getMsg();
    }

    public ServiceException(ResponseCodeEnum rCode) {
        this(rCode, rCode.getMessage());
    }

    public ServiceException(ResponseCodeEnum rCode, String message) {
        super(message);
        this.result = R.fail(rCode, message);
        this.message = message;
    }

    public ServiceException(Integer rCode, String message) {
        super(message);
        this.result = R.fail(rCode, message);
        this.message = message;
    }

    public ServiceException(String message) {
        super(message);
        this.result = null;
        this.message = message;
    }

    public ServiceException(Throwable cause) {
        this(cause.getMessage(), cause);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
        doFillInStackTrace();
        this.result = null;
        this.message = message;
    }

    @Nullable
    public <T> R<T> getResult() {
        return (R<T>) result;
    }

    public String getMessage(){
        return this.message;
    }

    public void setMessage(String message){
        this.message = message;
    }

    /**
     * 提高性能
     * @return Throwable
     */
    @Override
    public synchronized Throwable fillInStackTrace() {
        return this;
    }

    public Throwable doFillInStackTrace() {
        return super.fillInStackTrace();
    }

}